// 组合

// 借助纯函数和柯里化，容易写出洋葱代码 `f(g(x))`

// 函数组合可以让我们把细粒度的函数组合成功能强大的新函数

// 管道 linux ls | grep function

// 函数组合：如果一个数据要经过多个函数处理才能得到最终值，这个时候可以把中间过程的函数合并成一个函数

// 函数就像是数据的管道，函数组合就是把这些管道连接起来，让数据穿透过多个管道形成最终结果
// 函数组合默认是从右到左的执行

// function compose(f, g) {
//   return function (value) {
//     return f(g(value));
//   };
// }

const compose = (...args) => (value) =>
  args.reverse().reduce((acc, fn) => fn(acc), value);

function first(arr) {
  return arr[0];
}

function upperCase(str) {
  return str.toUpperCase();
}

// const firstUpperCase = compose(upperCase, first);

// console.log(firstUpperCase(['a', 'b']));

// function compose(...args) {
//   // f g h -> f(g(h()))
//   return function (value) {
//     return args.reverse().reduce((acc, fn) => {
//       return fn(acc);
//     }, value);
//   };
// }
function charCodeAt(str) {
  return str.charCodeAt();
}

function sayResult(value) {
  console.log(`The final result is: ${value}`);
}
compose(sayResult, charCodeAt, upperCase, first)(['c', 'b']);

// 函数组合要满足组合律

// compose(compose(f, g), h) === compose(f, compose(g, h))

// 如何调试组合函数

const _ = require('lodash');

const split = _.curry((sep, str) => _.split(str, sep));

const map = _.curry((fn, arr) => _.map(arr, fn));

const join = _.curry((str, arr) => _.join(arr, str));

const trace = _.curry((tag, v) => {
  console.log(tag, v);
  return v;
});
const f = _.flowRight(
  join('-'),
  trace('map'),
  map(_.toLower),
  trace('split'),
  split(' ')
);

console.log(f('NEVER SAY DIE'));

// lodash本身提供的模块并不是函数式编程的风格，所以需要我们自己去封装
// 每个函数的柯里化，lodash也不满足Pointfree。Ramda在设计之前是非常
// 符合函数式编程的思想

// 意识到这块的问题之后，lodash也提供了fp模块来支持函数式编程

const fp = require('lodash/fp');

const f1 = fp.flowRight(fp.join('-'), fp.map(fp.toLower), fp.split(' '));

console.log(f1('NEVER SAY DIE'));
